package com.miraclesea.component.log.asserts;

import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import com.miraclesea.framework.exception.LogicException;
import com.miraclesea.framework.exception.UserException;
import com.miraclesea.framework.lang.Constants;

public final class LogAssert {
	
	private LogAssert() { }
	
	public static void assertTrace(final String traceLog, final MethodInstance methodInstance) {
		String[] traceLogs = traceLog.split(Constants.LINE_SEPARATOR);
		String srartLinePattern = " --main-- Call: public abstract %s com.miraclesea.component.log.TestLog.%s(%s) ";
		String startLine = String.format(srartLinePattern, methodInstance.getReturnType(), methodInstance.getMethodName(), methodInstance.getArguments().getTypes());
		boolean found = false;
		int count = 0;
		for (String line : traceLogs) {
			if (line.endsWith(startLine)) {
				found = true;
				assertTraceArgumentsLine(traceLogs[count + 1], methodInstance.getArguments());
				if (methodInstance.hasException()) {
					assertTraceExceptionLine(traceLogs[count + 2], methodInstance.getException());
				} else {
					assertReturnValueLine(traceLogs[count + 2], methodInstance.getReturnValue());
				}
				break;
			}
			count++;
		}
		assertTrue(String.format("Cannot contains %s", startLine), found);
	}
	
	private static void assertTraceArgumentsLine(final String traceLogParameterLine, final Arguments arguments) {
		if (arguments.hasArguments()) {
			assertThat(traceLogParameterLine, 
					endsWith(String.format(" --main-- There are %d parameter(s), value(s) are: %s", arguments.getLength(), arguments.getValues())));
		} else {
			assertThat(traceLogParameterLine, endsWith(" --main-- There is not any parameter "));
		}
	}
	
	private static void assertTraceExceptionLine(final String traceLogExceptionLine, final Exception ex) {
		if (ex instanceof UserException) {
			UserException userException = (UserException) ex;
			String linePattern = "--main-- Got an user exception. Error code is: %s, argument(s) are: %s ";
			assertThat(traceLogExceptionLine, endsWith(String.format(linePattern, userException.getErrorCode(), userException.getArguments())));
		} else if (ex instanceof LogicException) {
			assertThat(traceLogExceptionLine, endsWith(String.format("--main-- Got an logic exception. It is: %s ", ex)));
		}
	}
	
	private static void assertReturnValueLine(final String returnValueLine, final Object returnValue) {
		assertThat(returnValueLine, endsWith(String.format(" --main-- Execute completed, the return value is: %s ", returnValue)));
	}
	
	public static void assertPerformance(final String performanceLog, final MethodInstance methodInstance) {
		String[] performanceLogs = performanceLog.split(Constants.LINE_SEPARATOR);
		String linePartPattern = "--main-- Method signature: public abstract %s com.miraclesea.component.log.TestLog.%s(%s), Spend time is: ";
		String linePart = String.format(linePartPattern, methodInstance.getReturnType(), methodInstance.getMethodName(), methodInstance.getArguments().getTypes());
		boolean found = false;
		for (String line : performanceLogs) {
			if (line.contains(linePart)) {
				found = true;
				break;
			}
		}
		assertTrue(String.format("Cannot contains %s", linePart), found);
	}
	
	public static void assertError(final String errorLog, final MethodInstance methodInstance) {
		String[] errorLogs = errorLog.split(Constants.LINE_SEPARATOR);
		String linePart = String.format("--main-- Got an unexpected exception. It is: %s", methodInstance.getException());
		boolean found = false;
		int count = 0;
		for (String line : errorLogs) {
			if (line.endsWith(linePart)) {
				found = true;
				assertThat(errorLogs[count + 1], is("Replay the method call scenario..."));
				String signaturePattern = "Call: public abstract %s com.miraclesea.component.log.TestLog.%s(%s)";
				assertThat(errorLogs[count + 2], is(String.format(
						signaturePattern, methodInstance.getReturnType(), methodInstance.getMethodName(), methodInstance.getArguments().getTypes())));
				if (methodInstance.getArguments().hasArguments()) {
					String parameterLinepattern = "There are %d parameter(s), value(s) are: %s";
					assertThat(errorLogs[count + 3], endsWith(String.format(
							parameterLinepattern, methodInstance.getArguments().getLength(), methodInstance.getArguments().getValues().trim())));
				} else {
					assertThat(errorLogs[count + 3], endsWith("There is not any parameter "));
				}
				break;
			}
			count++;
		}
		assertTrue(String.format("Cannot contains %s", linePart), found);
	}
}
